/** 
* @file main.cpp
* Kernel main initialization code.
*
* Copyrights 2010 Michal Saman, m.saman@designplus.cz.
* This source code is release under the Apache License 2.0.
* http://www.apache.org/licenses/LICENSE-2.0
*/

#include <errno.h>
#include <hal/hal.h>
#include <drivers/ata/ata.h>
#include <drivers/pci/pci.h>
#include <cpu/exception.h>
#include <main/kprintf.h>
#include <main/textconst.h>
#include <main/boot_info.h>
#include <mem/mem.h>
#include <mem/pmu.h>
#include <mem/vmu.h>
#include <mem/kheap.h>
#include <proc/process.h>
#include <tsh/tsh.h>

extern	uint32_t	_bss_size;
extern	uint32_t	_end_loc;

/**
* Kernel main initialization function.
* @param boot_info	Multiboot structure obtained from bootloader.
*/
int __attribute__ ((cdecl)) main() {
	uint32_t kernel_size = 0;
	uint32_t sector_size = 0;
	__asm__ volatile ("mov %%edi, %0" : "=r"(sector_size) );
	__asm__ volatile ("mov %%edx, %0" : "=r"(kernel_size) );
	uint32_t kernel_init_alloc_size = (int)(&_end_loc) - 1048576;
	uint32_t memoffset = 0x100000;

	vga_text_mode_get_cursor_pos();
	vga_text_mode_set_color(0xE);

	kprintf("\nR-KERNEL %s started\n", rkernel_ver);
	kprintf("Kernel image size: %i sectors, %i kB\n", kernel_size, (kernel_size*sector_size)/1024 );
	kprintf(".bss section size 0x%x B, loaded kernel memory size %i kB\n", &_bss_size, kernel_init_alloc_size/1024);

	vga_text_mode_set_color(0xF);
	kprintf("\n# Initializing Hardware Abstraction Layer [HAL]\n");
	hal_init();

	kprintf("Binding basic system exceptions handlers\n");
	exceptions_install();

	// Init Physical Memory Manager
	kprintf("# Initializing PMU\nMemory map stored at address: 0x%x (%i kB)\n", memoffset + kernel_init_alloc_size, (memoffset + kernel_init_alloc_size)/1024);
	// We place pmu_memory_map to at the end of kernel code in memory
	memoffset += kernel_init_alloc_size;
	pmu_init(memoffset);
	memoffset += pmu_get_memory_map_size();

	// Paging init
	kprintf("# Initializing VMU\n");
	vmu_init();

	// KERNEL HEAP INIT
	kprintf("# Initializing kernel memory HEAP\n");
	kheap_init();			// place 1Mb kheap to 10Mb virtual address

	if (_kheap) {
		kprintf("Kernel HEAP initialized\n");
		kprintf("  --> avail. size: ~%i MB, start at: 0x%x, end at: 0x%x\n", _kheap->size/1024/1024, _kheap->start_address, _kheap->end_address );
	} else {
		kernel_panic("Can't initialize kernel memory HEAP.\n");
	}

	// reinit kernel stack
	kprintf("# Initializing kernel stack\n");
	if (move_stack((void*)0xE0000000, (void*)_init_stack_addr, 0x9000, (stack_t*)&_kstack) == EOK) {
		kprintf("Kernel stack initialized\n");
		kprintf("  --> avail. size: ~%i kB, start at: 0x%x\n", _kstack.size/1024, _kstack.start_address );
	} else {
		kernel_panic("Can't initialize kernel stack.\n");
	}

	kprintf("PMU status: %i blocks, reserved blocks: %i, free blocks: %i\n",
		pmu_get_block_count(), pmu_get_use_block_count(), pmu_get_free_block_count() );

	//kheap_test();

	// PCI BUS INIT
	kprintf("# Initializing PCI\n");
	pci_init();

	// ATA INIT
	kprintf("# Initializing ATA controllers\n");
	ata_init();

	// MULTITASKING INIT
	kprintf("# Initializing multitasking subsystem.\n");
	proc_init();

	int fr = proc_fork();
	kprintf("fork returned PID: %u\n", fr);

	for(;;);

	//kprintf("Running process: %u\n", get_pid());
	//kprintf("R-KERNEL loading done. Welcome to ReindeerOS.\n");
	//tiny_shell_init();

	return 0;
}
